package com.qianlou.task;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

import com.qianlou.common.utils.GLMTokenUtils;
import com.qianlou.common.utils.JsonUtils;
import com.qianlou.config.GLMSdkProperties;
import com.qianlou.pojo.InterviewRecord;
import com.qianlou.pojo.Job;
import com.qianlou.pojo.bo.AnswerBO;
import com.qianlou.pojo.bo.SubmitAnswerBO;
import com.qianlou.pojo.glm.ChatGLMModel;
import com.qianlou.pojo.glm.EventType;
import com.qianlou.pojo.glm.GLMResponseV3;
import com.qianlou.service.InterviewRecordService;
import com.qianlou.service.JobService;
import jakarta.annotation.Resource;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import okhttp3.internal.sse.RealEventSource;
import okhttp3.sse.EventSource;
import okhttp3.sse.EventSourceListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import javax.annotation.Nullable;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Component
@Slf4j
public class ChatGLMTask {

    @Resource
    private GLMSdkProperties glmSdkProperties;

    @Resource
    private JobService jobService;

    @Resource
    private InterviewRecordService interviewRecordService;

    public static final Integer connectTimeout = 600;           // 连接超时时间
    public static final Integer writeTimeout = 500;             // 写操作超时时间
    public static final Integer readTimeout = 400;              // 读操作超时时间
    public static final Integer readAndWriteTimeout = 600;      // 读写操作超时时间

    /********** 请求头信息 **********/
    public static final String SSE_CONTENT_TYPE = "text/event-stream";
    public static final String DEFAULT_USER_AGENT = "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)";
    public static final String APPLICATION_JSON = "application/json";
    public static final String JSON_CONTENT_TYPE = APPLICATION_JSON + "; charset=utf-8";

    /**
     * api请求的调用方式
     *      invoke: 同步调用
     *      async-invoke: 异步调用
     *      sse-invoke: SSE 调用
     */
    public static final String apiUrl = "https://open.bigmodel.cn/api/paas/v3/model-api/" + ChatGLMModel.CHATGLM_4_Flash.key + "/sse-invoke";

    @Async
    public void display(SubmitAnswerBO submitAnswerBO) {
        log.info("开始异步AI智能分析...");

        String jobId = submitAnswerBO.getJobId();
        Job job = jobService.getById(jobId);
        if (job == null) {
            log.error("职位信息为空，jobId: {}", jobId);
            return;
        }

        /********** 拼接提示词与回答的文字内容 **********/
        final String PREFIX_QUESTION = "提问：";
        final String PREFIX_ANSWER = "正确答案：";
        final String PREFIX_USER_ANSWER = "回答内容：";

        List<AnswerBO> answerList = submitAnswerBO.getQuestionAnswerList();
        StringBuilder contentBuilder = new StringBuilder();
        for (AnswerBO answer : answerList) {
            contentBuilder.append(PREFIX_QUESTION).append(answer.getQuestion()).append("\n");
            contentBuilder.append(PREFIX_ANSWER).append(answer.getReferenceAnswer()).append("\n");
            contentBuilder.append(PREFIX_USER_ANSWER).append(answer.getAnswerContent()).append("\n\n");
        }

        String content = contentBuilder.toString();
        String submitContent = job.getPrompt() + "\n\n" + content;

        // 避免打印完整内容防止敏感信息泄露
        log.info("ChatGLMTask.submit 已组装完成，提交内容长度: {} 字符", submitContent.length());

        /********** 把内容提交到ChatGLM进行分析 **********/
        Request request;
        try {
            request = new Request.Builder()
                    .url(apiUrl)
                    .header("Authorization", GLMTokenUtils.generateToken(glmSdkProperties.getApiKey(), glmSdkProperties.getSecretKey()))
                    .header("Content-Type", JSON_CONTENT_TYPE)
                    .header("User-Agent", DEFAULT_USER_AGENT)
                    .header("Accept", SSE_CONTENT_TYPE)
                    .post(RequestBody.create(MediaType.parse("application/json"), generateBodyString(submitContent)))
                    .build();
        } catch (Exception e) {
            log.error("构建请求失败", e);
            return;
        }

        OkHttpClient okHttpClient = new OkHttpClient.Builder()
                .connectTimeout(connectTimeout, TimeUnit.SECONDS)
                .writeTimeout(writeTimeout, TimeUnit.SECONDS)
                .readTimeout(readTimeout, TimeUnit.SECONDS)
                .build();

        RealEventSource realEventSource = getRealEventSource(
                content,
                submitAnswerBO.getCandidateId(),
                job.getJobName(),
                submitAnswerBO.getTotalSeconds(),
                request);

        realEventSource.connect(okHttpClient);
    }

    private RealEventSource getRealEventSource(String answerContent, String candidateId, String jobName,Integer takeTime, Request request) {
        // 实例化EventSource，并注册EventSource监听器
        //System.out.println("获得事件");
        //                System.out.println(response);
        //                log.info("onEvent：{}", response.getData());
        // type消息类型：add-增量、finish-结束、error-错误、interrupted-中断
        //                    GLMResponseV3.Meta meta = JsonUtils.jsonToPojo(response.getMeta(), GLMResponseV3.Meta.class);
        //                    log.info("任务信息: {}", meta.toString());
        return new RealEventSource(request, new EventSourceListener() {

            String finalResult = "";

            @Override
            public void onEvent(EventSource eventSource, @Nullable String id, @Nullable String type, String data) {
                //System.out.println("获得事件");

                GLMResponseV3 response = JsonUtils.jsonToPojo(data, GLMResponseV3.class);
//                System.out.println(response);
                String result = response.getData();
                finalResult += result;
//                log.info("onEvent：{}", response.getData());
                // type消息类型：add-增量、finish-结束、error-错误、interrupted-中断
                if (EventType.FINISH.getKey().equals(type)) {
//                    GLMResponseV3.Meta meta = JsonUtils.jsonToPojo(response.getMeta(), GLMResponseV3.Meta.class);
//                    log.info("任务信息: {}", meta.toString());

                    InterviewRecord record = new InterviewRecord();
                    record.setCandidateId(candidateId);
                    record.setTakeTime(takeTime);
                    record.setJobName(jobName);
                    record.setAnswerContent(answerContent);
                    record.setResult(finalResult);
                    record.setCreateTime(LocalDateTime.now());
                    record.setUpdatedTime(LocalDateTime.now());

                    interviewRecordService.save(record);
                }
            }

            @Override
            public void onClosed(EventSource eventSource) {
                System.out.println("关闭链接事件");
            }

            @Override
            public void onOpen(EventSource eventSource, Response response) {
                System.out.println("打开链接事件");
            }

            @Override
            public void onFailure(EventSource eventSource, @Nullable Throwable t, @Nullable Response response) {
                System.out.println("失败事件");
            }
        });
    }

    @Data
    @Builder
    @NoArgsConstructor
    @AllArgsConstructor
    public static class Prompt {
        private String role;
        private String content;
    }

    public static String generateBodyString(String content) {

        String requestId = String.format("lee-%d", System.currentTimeMillis());
        float temperature = 0.9f;
        float topP = 0.7f;
        String sseFormat = "data";      // 数据格式
        boolean incremental = true;     // 增量式推送

        List<Prompt> promptList = new ArrayList<>();
        Prompt prompt = new Prompt();
        prompt.setRole("user");
        prompt.setContent(content);
        promptList.add(prompt);

        Map<String, Object> paramsMap = new HashMap<>();
        paramsMap.put("request_id", requestId);
        paramsMap.put("prompt", promptList);
        paramsMap.put("incremental", incremental);
        paramsMap.put("temperature", temperature);
        paramsMap.put("top_p", topP);
        paramsMap.put("sseFormat", sseFormat);
        try {
            return new ObjectMapper().writeValueAsString(paramsMap);
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }
    }
}
